package org.quipu.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.ejb.EJB;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.quipu.AppException;
import org.quipu.api.BookHelper;
import org.quipu.client.MainService;
import org.quipu.dto.AccountDto;
import org.quipu.dto.AccountDetailDto;
import org.quipu.dto.BookCacheDto;
import org.quipu.dto.BookDto;
import org.quipu.dto.BookUserDto;
import org.quipu.dto.CategoryDto;
import org.quipu.dto.CurrencyDto;
import org.quipu.dto.TagDto;
import org.quipu.dto.TransactionDto;
import org.quipu.dto.TransactionsFilterDto;
import org.quipu.dto.UserDto;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class MainServiceImpl extends RemoteServiceServlet implements MainService {

    @EJB
    private BookHelper bookHelper;
    private Logger logger = Logger.getLogger(getClass());
//    private UserDto user;

    @Override
    public UserDto getSessionUser() {
        HttpServletRequest request = this.getThreadLocalRequest();
        HttpSession session = request.getSession();
        Object userObj = session.getAttribute("user");
        if(userObj != null && userObj instanceof UserDto) {
            return (UserDto) userObj;
        } else {
            return null;
        }
    }

    @Override
    public void setSessionUser(UserDto user) {
        HttpServletRequest request = this.getThreadLocalRequest();
        HttpSession session = request.getSession();
//        session.invalidate();
        session.setAttribute("user", user);
    }

    private boolean checkUserSession() {
        return getSessionUser() != null;
    }

    @Override
    public List<BookDto> getBooks() throws AppException {
        UserDto user = getSessionUser();
        Long userId = (user != null? user.getId(): null);
        return bookHelper.getUserBooks(userId);
    }

    @Override
    public void submitBook(BookDto book) throws AppException {
        UserDto user = getSessionUser();
        if(user != null) {
            bookHelper.submitBook(book, user.getId());
        } else {
            throw new AppException("Not authenticated");
        }
    }

    @Override
    public void removeBook(Long bookId) throws AppException {
        bookHelper.removeBook(bookId);
    }

    @Override
    public BookCacheDto getBookCache(Long bookId, Long userId) throws AppException {
        return bookHelper.getBookCache(bookId, userId);
    }

    @Override
    public void submitAccount(AccountDto account) throws AppException {
        bookHelper.createOrUpdateAccount(account);
    }

    @Override
    public void removeAccount(Long accountId) throws AppException {
        bookHelper.removeAccount(accountId);
    }
/*
    public String getBooks() throws IllegalArgumentException {

//      List<String> books = new LinkedList<String>();
        String books = "";
        int booksCount = (int) (Math.random() * 10 + 1);
        for (int i = 1; i <= booksCount; i++) {
            books += ";Book #" + i;
        }
        String login = "foouser";
        try {
            bookHelper.getUserBooks(login);
        } catch(AppException ex) {
            logger.warn("Failed to get books list for user " + login, ex);
        }
        return books;
    }*/

    /**
     * Escape an html string. Escaping data received from the client helps to prevent cross-site script
     * vulnerabilities.
     *
     * @param html the html string to escape
     * @return the escaped string
     */
    private String escapeHtml(String html) {
        if (html == null) {
            return null;
        }
        return html.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
    }

    public UserDto authenticate(String login, String password) throws AppException {
        if("guest".equals(login) && "123".equals(password)) {
            UserDto user = new UserDto();
            user.setId(1L);
            user.setLogin("guest");
            setSessionUser(user);
            return user;
        } else {
            throw new AppException("Invalid password");
        }
    }

    @Override
    public void logout() throws AppException {
        setSessionUser(null);
    }

    @Override
    public BookUserDto getBookUser(Long bookId) throws AppException {
        UserDto user = getSessionUser();
        Long userId = (user != null? user.getId(): null);
        return bookHelper.getBookUserDto(bookId, userId);
    }

    @Override
    public List<AccountDetailDto> getBookAccountsCalculation(Long bookId, Date date, boolean approvedOnly) throws AppException {
        return bookHelper.getBookAccountsCalculation(bookId, date, approvedOnly);
    }

    @Override
    public List<AccountDto> getBookAccounts(Long bookId) throws AppException {
        return bookHelper.getBookAccounts(bookId);
    }

    @Override
    public List<CurrencyDto> getBookCurrencies(Long bookId) throws AppException {
        return bookHelper.getBookCurrencies(bookId);
    }

    @Override
    public List<TagDto> getBookTags(Long bookId) throws AppException {
        return bookHelper.getBookTags(bookId);
    }

    @Override
    public List<CategoryDto> getBookInCategories(Long bookId) throws AppException {
        return bookHelper.getBookCategoriesTree(bookId, CategoryDto.Type.INCOME);
    }

    @Override
    public List<CategoryDto> getBookOutCategories(Long bookId) throws AppException {
        return bookHelper.getBookCategoriesTree(bookId, CategoryDto.Type.OUTCOME);
    }

    @Override
    public void submitCategory(CategoryDto category) throws AppException {
        bookHelper.createOrUpdateCategory(category);
    }

    @Override
    public void removeCategory(Long categoryId) throws AppException {
        bookHelper.removeCategory(categoryId);
    }

    @Override
    public void submitCurrency(CurrencyDto currency) throws AppException {
        bookHelper.createOrUpdateCurrency(currency);
    }

    @Override
    public void removeCurrency(Long currencyId) throws AppException {
        bookHelper.removeCurrency(currencyId);
    }

    @Override
    public void submitTransaction(TransactionDto transaction) throws AppException {
        bookHelper.submitTransaction(transaction);
    }

    @Override
    public void detachTransaction(TransactionDto transaction, Long originalId) throws AppException {
        bookHelper.detachTransaction(transaction, originalId);
    }

    @Override
    public void removeTransaction(Long transactionId) throws AppException {
        bookHelper.removeTransaction(transactionId);
    }

    @Override
    public void submitTag(TagDto tag) throws AppException {
        bookHelper.submitTag(tag);
    }

    @Override
    public void removeTag(Long tagId) throws AppException {
        bookHelper.removeTag(tagId);
    }

    @Override
    public List<TransactionDto> getBookTransactions(Long bookId, TransactionsFilterDto filter, int page, int pageSize) throws AppException {
        return bookHelper.findTransactions(bookId, filter, page, pageSize);
    }

    @Override
    public List<Map<Long, Double[]>> getBalanceArchive(Long bookId, Date dateFrom, Date dateTo, boolean approvedOnly) throws AppException {
        return bookHelper.getBalanceArchive(bookId, dateFrom, dateTo, approvedOnly);
    }
}
